package helper

import (
	b64 "encoding/base64"
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/valyala/fasthttp"
	"github.com/xxtea/xxtea-go/xxtea"
	"lukechampine.com/frand"
	"math/rand"
	"strconv"
	"strings"
	"time"
	"unicode"
)

/*
const (
	TYpeNone = iota
	TypePhone
	TypeBankCardNumber
	TypeVirtualCurrencyAddress
	TypeRealName
	TypeEmail
)
*/

var (
	validateH5      = ""
	validateHT      = ""
	validateWEB     = ""
	validateAndroid = ""
	validateIOS     = ""
	isDev           bool
)

type Response struct {
	Status bool        `cbor:"status" json:"status"`
	Data   interface{} `cbor:"data" json:"data"`
}

func Use(h5, ht, web, android, ios string, dev bool) {

	validateH5 = h5
	validateHT = ht
	validateWEB = web
	validateAndroid = android
	validateIOS = ios
	isDev = dev
}

type NewResponse struct {
	Code int         `cbor:"code" json:"code"`
	Msg  string      `cbor:"msg" json:"msg"`
	Data interface{} `cbor:"data" json:"data"`
}

func RetData(fctx *fasthttp.RequestCtx, status bool, data interface{}) {
	fctx.SetStatusCode(200)
	code := 0
	msg := "成功"
	if status == false {
		code = 1
		// 类型断言 + 安全判断
		if str, ok := data.(string); ok {
			msg = str
		} else {
			msg = "未知错误"
		}
		data = nil
	}
	res := NewResponse{
		Code: code,
		Msg:  msg,
		Data: data,
	}

	bytes, err := JsonMarshal(res)
	//bytes, err := json.Marshal(res)
	if err != nil {
		fctx.SetBody([]byte(err.Error()))
		return
	}
	fctx.SetBody(bytes)
	return
}

func Print(fctx *fasthttp.RequestCtx, status bool, data interface{}) {

	fctx.SetStatusCode(200)

	res := Response{
		Status: status,
		Data:   data,
	}

	bytes, err := JsonMarshal(res)
	//bytes, err := json.Marshal(res)
	if err != nil {
		fctx.SetBody([]byte(err.Error()))
		return
	}
	fctx.SetBody(bytes)
	return
}

func PrintJson(fctx *fasthttp.RequestCtx, state bool, data string) {

	fctx.SetStatusCode(200)

	builder := strings.Builder{}
	builder.WriteString(`{"status":`)
	builder.WriteString(strconv.FormatBool(state))
	builder.WriteString(`,"data":`)
	builder.WriteString(data)
	builder.WriteString("}")
	str := builder.String()

	if isDev {
		fctx.SetContentType("application/json")
		fctx.SetBody([]byte(str))
		return
	}

	device := string(fctx.Request.Header.Peek("d"))
	keys := ""
	switch device {
	case "23":
		keys = validateHT
	case "24":
		keys = validateWEB
	case "25":
		keys = validateH5
	case "35":
		keys = validateAndroid
	case "36":
		keys = validateIOS
	}
	if keys == "" {
		fctx.SetContentType("application/json")
		fctx.SetBody([]byte(str))
		return
	}
	encryptData := xxtea.Encrypt([]byte(str), []byte(keys))
	sEnc := b64.StdEncoding.EncodeToString(encryptData)
	fctx.SetContentType("text/plain")
	fctx.SetBody([]byte(sEnc))
}

func GenId() string {

	var min uint64 = 0
	var max uint64 = 9

	return fmt.Sprintf("%d%d", Cputicks(), frand.Uint64n(max-min)+min)
}

func GenLongId() string {

	var min uint64 = 100000
	var max uint64 = 999999

	id := fmt.Sprintf("%d%d", Cputicks(), frand.Uint64n(max-min)+min)
	return id[0:18]
}

func CtypeCommaDigit(s string) bool {

	if s == "" {
		return false
	}
	for _, r := range s {
		if (r < '0' || r > '9') && r != ',' {
			return false
		}
	}
	return true
}

func CtypePunct(s string) bool {

	if s == "" {
		return false
	}
	for _, r := range s {
		if unicode.IsPunct(r) || unicode.IsSpace(r) {
			return true
		}
	}
	return false
}

// 判断字符串是不是数字
func CtypeDigit(s string) bool {

	if s == "" {
		return false
	}
	for _, r := range s {
		if !unicode.IsDigit(r) {
			return false
		}
	}
	return true
}

// 判断字符串是不是字母+数字
func CtypeAlnum(s string) bool {

	if s == "" {
		return false
	}

	for _, r := range s {
		if !unicode.IsDigit(r) && !unicode.IsLetter(r) {
			return false
		}
	}
	return true
}

// 获取source的子串,如果start小于0或者end大于source长度则返回""
// start:开始index，从0开始，包括0
// end:结束index，以end结束，但不包括end
func Substring(source string, start int, end int) string {

	var r = []rune(source)
	length := len(r)

	if start < 0 || end > length || start > end {
		return ""
	}

	if start == 0 && end == length {
		return source
	}

	return string(r[start:end])
}

// 字符串特殊字符转译
func Addslashes(str string) string {

	tmpRune := []rune{}
	strRune := []rune(str)
	for _, ch := range strRune {
		switch ch {
		case []rune{'\\'}[0], []rune{'"'}[0], []rune{'\''}[0]:
			tmpRune = append(tmpRune, []rune{'\\'}[0])
			tmpRune = append(tmpRune, ch)
		default:
			tmpRune = append(tmpRune, ch)
		}
	}

	return string(tmpRune)
}

func TrimStr(val decimal.Decimal) string {

	s := "0.000"
	sDigit := strings.Split(val.String(), ".")
	if len(sDigit) != 2 {
		if len(sDigit) == 1 && CtypeDigit(sDigit[0]) {
			return sDigit[0] + ".000"
		}
		return s
	}

	// 浮点位数校验
	if len(sDigit[1]) <= 3 {
		return val.String()
	}

	return sDigit[0] + "." + sDigit[1][:3]
}

func RandomKey(length int) string {

	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	var result []byte
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < length; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

func RandomGoogleKey() string {

	str := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	var result []byte
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < 16; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}

	return string(result)
}

func RandomNum(length int) string {

	str := "0123456789"
	bytes := []byte(str)
	var result []byte
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < length; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

func TrimPrefixSuffix(in, fix string) string {

	if strings.HasPrefix(in, fix) {
		in = strings.TrimPrefix(in, fix)
		return TrimPrefixSuffix(in, fix)
	}

	if strings.HasSuffix(in, fix) {
		in = strings.TrimSuffix(in, fix)
		return TrimPrefixSuffix(in, fix)
	}

	return in
}
